## Teach Yourself ActiveX in 21 Days

- CGI
  - CGI Creation
    - CGI Script Installation
  - CGI Operation
    - Command-line Parameters and Environment Variables
    - Standard Input
    - Standard Output
  - Using CGIs with HTML Forms
- ISAPI Programming
  - Executables Versus Dynamic Link Libraries
    - Executables
    - Dynamic Link Libraries
  - In-Process Versus New Process
  - HTTP and ISAPI Interaction
    - The Extension Control Block
    - Entry Points
    - ISAPI Functions
  - Considerations for Building an ISAPI DLL
    - HTTPExtensionProc
    - Access Violations
    - DLLMain
    - Logging
  - Converting CGI to ISAPI
    - StdIn/StdOut to ECB
- Summary
- Q&A
- Workshop
- Quiz

#
— 11 —

##
Server Side Scripting with CGI and ISAPI

The Internet Server Application Programmers Interface (ISAPI) is a tool with which ActiveX programmers can write server-side scripts. These server scripts are the "next generation" of the CGI (Common Gateway Interface).

These kinds of scripts are run through your HTTP daemon (server). The scripts act as an interface between the users (and their software) and the server (and its software).

Without server scripting, Web surfing is relegated to simply serving up and viewing static documents. The users can't interact with these documents, and features such as HTML forms and clickable image maps become impossible.

In this chapter you will become acquainted with writing both CGI and ISAPI applications.

###
CGI

Before we get into the meat and potatoes of this, let's take a look at the words CGI represents: Common Gateway Interface.

Common means that this scripting specification is used with a variety of different HTTP server software packages. This allows programmers to be relatively certain that a CGI script that is written for a package like O'Reilly's WebSite will still work on Microsoft's Internet Information Server as well as Netscape HTTP server or any of the shareware and freeware servers out there—as long as they support CGI.

> > Note
> > You will frequently hear of an Internet server (be it SMTP, FTP, or HTTP) referred to as a daemon (pronounced dee-muhn). They get this name from the early days of the commercial Internet, when server packages were mostly limited to use on UNIX. Any UNIX-hound can tell you that these suckers were devilishly difficult to set up and maintain. Since then they have become much simpler to operate—although most features have become much more powerful.

Gateway interface means that this scripting specification is used to allow network access to local programs. (See Figure 11.1) In and of itself, this is not very spectacular, but in the interest of security, you do not want to allow network access to just any old program or data file. Some of these files are just too sensitive.

Figure 11.1. CGI and ISAPI Scripts act as an interface between a local user and an external program located on the remote HTTP server.

Gateways also provide the interface for allowing users to interact with Web content through clickable images and forms. Then, when the user selects whatever options he wants in the forms and images, the gateway can take that input and return dynamic content. This means that the document that is returned to the client may not actually exist until the user requests it. The gateway does this by taking the input provided by the user and creating a document on-the-fly that meets the user's request.

One example of these gateway interfaces is ODBC (Open DataBase Connectivity). ODBC is the database feature of Windows that allows the system to access any of a number of different kinds of databases without having to launch a full-blown database application. Web services do not generally know how to access a database, so they need a gateway between the user and the ODBC driver.

> > Hint
> > Microsoft has been very good about ensuring that powerful database features have been implemented in every evolution of the ActiveX technologies. This especially includes its ODBC system, which is designed to make databases accessible from a large number of interfaces. Thus the word open in Open Database Connectivity.
> > Included in the MS Internet Information Server installation is a DLL appropriately named HTTPODBC.DLL. It works with any of a number of IDCs (Internet Database Connectors) for different kinds of databases. This .IDC file is then used to specify a data source, define allowable queries, and specify the file that will act as an HTML template within which the results of the query will be returned to the client. The template will usually have an .HTX (hypertext extension) filename extension.

The user's request is translated by the gateway into a process that the ODBC system can understand. Then, when ODBC returns its results, the gateway creates an HTML document based on those results. That's dynamic content.

> > Hint
> > As you create your CGI and ISAPI applications, bear in mind that most Web surfers require instant gratification. When a user requests a document (that is, runs a script), he won't wait very long for your program to return the results.
> > Make sure to test your applications for speed as well as for accuracy and bugginess. A slow server is a server that users will avoid.

####
CGI Creation

CGIs can be created with any of a number of different languages. They come in two flavors—scripted and compiled. Either way they will work in the same manner, which I will describe throughout this chapter.

If you want to compile your CGI script into an .exe or .dll file, you will need to use a programming language like C, C++, or Visual Basic. These languages create a binary file that many newer programmers prefer.

The preference of a programming language over a scripting language is due, for the most part, to the power and ease with which compiled applications are developed. Most have some sort of windowed design interface that aids in the creation of the CGI. Visual Basic, for instance, uses a context-sensitive help system and will even reformat and capitalize your code as you type. (See Figure 11.2.)

Figure 11.2. Visual Basic includes a context-sensitive help system and will alert you to many errors even while you are making them.

Alternatively, most seasoned Internet programmers prefer to use one of the scripting languages of the Internet such as Perl, UNIX shell, or even AppleScript. There are several good reasons for using a script instead of a compiled application. For one, scripts are just text files.

Real-time editing and debugging of these scripts is quick and simple because you don't have to recompile every time. Also, because they are text files, they can usually be edited and tested from a remote location, whereas compiled binaries have to be deleted from the CGI-BIN directory, recompiled, and then re-sent to the server before they can be tested.

#####
CGI Script Installation

For security reasons, CGIs are normally kept in a restricted-access directory. This directory is usually named something like \cgi-bin\ or a derivative thereof. Most ISPs will not allow users to upload their CGIs directly to this directory, although they can always retrieve information from that directory.

The potential threat from which ISPs want to protect themselves comes in the form of malicious or undesirable functions being called by the script. For example, if you were to create a script, and it had a bug that placed it into some sort of endless loop, the system resources used by that script could not be recovered until a human being came along and reset the server.

If the flawed CGI script were called several times before the Webmaster gets around to fixing it, the system could hang and crash. This would crash the Web site for every single one of the ISP's users. Such a disaster would put the ISP in hot water with hundreds of users, and would cost them and their users several more thousands of dollars each. It would also, most likely, cost you your Web privileges. This is a good argument for debugging your programs.

For this reason, many ISPs require you to send your CGI to an individual within its organization. That individual has the responsibility of crash-testing the script to find hidden hazards before they can cause any serious grief. Only then is the script posted to the CGI directory. This process can take days or weeks. This is a good argument for having a strong, trusting relationship with your Internet provider.

####
CGI Operation

The concept behind CGI programming is pretty simple. The CGI takes command-line parameters and environment variables and something called StdIn (standard input) and returns a document through the StdOut (standard output).

#####
Command-line Parameters and Environment Variables

In a standard DOS or Windows environment, programs can be launched with a command-line parameter . This means, for example, that if you were to type the following at a prompt

    MyProgram.exe Parameter1 Parameter2

the program MyProgram.exe would be launched, and it would use the parameters Parameter1 and Parameter2 as part of the start process.

When a user requests a CGI from an HTTP server, it usually does so while passing a set of parameters, but these may not always be passed to the CGI as command-line parameters. Usually, the URL parameters are passed to the CGI through environment variables instead. For example:

    Http://www.MyDomain.Net/MyDir/MyCGI.exe?Bucky

In this example, "Bucky" would be passed to the CGI application MyCGI.exe as a command-line parameter. This would cause the server to execute the command MyCGI.exe Bucky. An example of a CGI request that would pass the parameters through an environment variable instead of a command line would look like this:

    Http://www.MyDomain.Net/MyDir/MyCGI.exe?MyName=Bucky

In this example, Bucky would not be passed to the CGI application as a parameter. Instead the HTTP daemon would set an environment variable called MyName to the value Bucky. This would cause the server to execute the command MyCGI.exe all by itself. It is up to the CGI script itself to retrieve data from the variable.

The = is the key here. If there is no equal sign, the query string (everything after the ?) is passed to the CGI application as a command-line parameter.

If there exists an = anywhere in the query string, everything to the left of the equal sign is treated as an environment variable to be set. Everything to the right of the equal sign is treated as a value to be assigned to that environment variable.

HTTP Query Syntax

    [URL]\[CGI]?[parameter]

or

    [URL]\[CGI]? [Environment Variable]=[Value] &[Environment Variable]=[Value]

A CGI program is usually launched by a client request in the form of an HTTP query. The query can be formatted to send a command-line variable to the CGI or to set one or more environment variables to be used by the CGI in its operation. The parameter will be sent to the CGI on the command line unless there is an = in the query string. If there is an equal sign, the parameters will be used to send environment variables.

For example:

This line would launch MyCGI.exe Parm1 from the command line:

    http://www.MyDomain.net/MyCGI.exe?Parm1

This line would launch MyCGI.exe from the command line and set the environment variable for Couple to the value of 2 and for Few to the value of 3:

    http://www.MyDomain.net/MyCGI.exe?Couple=2&Few=3

This is a good time to mention the & (ampersand) character as well. Some of the more popular search engines (such as Yahoo! [Figure 11.3] and WebCrawler) use CGIs that require several different environment variables to be set. In this case, each variable and its associated value is set off from the one before it with an ampersand:

    Http://www.MyDomain.net/MyDir/MyCGI.exe?DOSCommand=Format&Drive=C&Parm=u

In this example, the server would set three environment variables. The variable DOSCommand would be set to the value Format, the variable Drive would be set to C, and the variable Parm would be set to u. It would not pass any command-line parameters to MyCGI.exe because there was an = in the query string.

Another way the & character is used is in string concantenation . String concatenation is when you append an entire string to the end of another string. For example, suppose you had to form fields (HTML or VB—It doesn’t matter). One of them contains an Area Code value and the other contains a Phone Number value. You may not care to separate the two for this particular form, since you are treating both as one string; so you concatenate the two with an & character like so:

    Dim strAreaCode as String
    Dim strPhoneNumber as String
    Dim strBothNumbers as String
    strBothNumbers = strAreaCode & strPhoneNumber

This would set the value of strBothNumbers to the area code with the phone number appended to it.

Many tutorials teach that the + sign can be used instead of the & sign to achieve the same concatenation results. This is sometimes true. If you use the + sign with two string values, both of which begin with letters instead of numbers, the two may concatenate well. If, however, one of those variables has not already been defined as a string or begins with an integer, unexpected results may occur.

Figure 11.3. The Yahoo! search server uses a CGI format that sends the data that is used in the search through environment variables.

#####
Standard Input

Standard input (StdIn) is the information that is sent from the client to the script server with an HTTP Put or Post method. It refers to two variables—Content_Length and Content_Type.

Content_Type is the MIME type for the object that is being sent to the server script as data. This could be a picture, video, sound, or just about anything that can exist on a computer (except, maybe, a dust cover). If the data being sent is a Web form, the MIME type is application/x-www-form-urlencoded.

Content_Length is the size of the data stream being sent to the script server. Take note that this is represented in bytes—not bits or kilobytes.

#####
Standard Output

After the script server receives the StdIn, it performs any functions contained within the script and returns the Standard output (StdOut). This can be a document that goes back to the client that made the CGI request, or it can be instructions to the HTTP daemon as to what information the daemon should send back to the client. Either way, the StdOut consists of just a few headers and a data stream of some kind.

In the StdOut you can perform any one of four functions:

- Return a reference to a remote document
- Return a reference to a local document
- Return a document
- Return a document with headers

If the end result of the CGI is to simply send a file that already exists on some remote server to the client, all you have to do is send a Location: header followed by the full URL of the remote document, like this:

    Location: http://www.OtherDomain.net/OtherDir/Other.html

If the result of the CGI is to send a file that already exists on the same server as the CGI, you send that same Location: header, only this time you need only follow it with the relative path, like this:

    Location: /MyDir/MyFile.html

If the CGI result is to send a file it created by itself, on-the-fly, you need to send the Content-Type: header followed by a blank line and the document data:

    Content-type: text/iuls

This line would let the server take care of passing the HTTP header information to the client, but in some cases it may be necessary, expedient, or just downright fun to send the header information yourself while preventing the HTTP daemon from sending that same type of header information. Also, by not requiring the HTTP daemon to process your HTTP headers, the execution speed of the CGI is increased somewhat.

Should you choose to send the header information yourself, you can report various information back to the client. This includes such things as the level of HTML that you support, and the name and version number of the application you are using. This information can be important when your users are scanning through their log files, trying to identify which programs performed what actions on their machines.

The way you tell the server that your CGI is going to talk to the client directly is to meet these two requirements:

- Prefix the filename of your CGI with nph- (for example, nph-MyScript.exe).
- Have the script send the appropriate HTTP headers that the server would have.

An StdOut that the CGI returns in this manner would look something like this:

    HTTP/1.0 200 OK
    Server: MyProprietaryServer/1.9b1
    Content-type: text/html
    <HTML>
    <HEAD> <TITLE> My Document </TITLE> </HEAD>
    <BODY>
    <p>This is my document</p>
    </BODY>
    </HTML>

####
Using CGIs with HTML Forms

Now that you know how data is sent to the script server from the client, as well as how response data is sent back to the client from the script server, now you can learn how an HTML form is used to command a client to start sending that data.

How these forms are placed within an HTML document is a topic that will be covered in the last seven chapters of this book. An example of one, however, can be seen in Figure 11.3.

For now, it should be enough to know that there are two different methods that an HTML Form can use to interact with CGI—"Get" and "Post".

In the Get method, all the information that follows the ? on the URL line is placed in the environment variable Query_String. It is then up to the CGI program to parse that string appropriately to retrieve the data that the user entered into the HTML form.

In the Post method, the user-specified HTML form information is sent to StdOut. This is sent as a block of HTTP data, rather than an extended URL such as in the Get method.

From the data stream of a Post method itself, there is really no way for your CGI to automatically know when it has received all of the data that was sent from the client. As a result, your CGI must determine the length of the string in bytes from the Content_Length environment variable. Then it will use that byte count to figure out when it has received everything that was to be transmitted.

###
ISAPI Programming

Repeating what I mentioned earlier, ISAPI is not just a replacement for CGI—it's a strong enhancement to it. CGI is used on almost every kind of HTTP daemon, but it is not OLE capable like ISAPI. As a result, CGI scripts require more overhead in terms of memory and system resources.

####
Executables Versus Dynamic Link Libraries

A gateway interface can be compiled in one of two ways. It can be compiled into an executable (.exe) or into a Dynamic Link Library (.DLL). Although each has its own benefits as well as drawbacks, DLLs are the preferred form. Both are referred to as PEs (portable executables).

#####
Executables

If you are at all familiar with compiling programs (as you should be if you are reading this book), you already know how to compile an executable (.exe) file.

Whey you create this type of file, you are creating something that can be run from the operating system's command line.

#####
Dynamic Link Libraries

A dynamic link library (.dll file) is a bit more complex to create. When you create this type of file, you are creating something that can not be run from the operating system's command line, but rather is called by some other process external to the .dll itself.

When an external process makes a call to a .DLL, it does not actually "run" the library, but rather makes reference to a procedure within that library. These calls are often referred to as API calls. When you create an ISAPI .DLL, you are creating an ActiveX OLE control. This calling of a process within a .DLL is called linking. Two types of linking can be used with ActiveX DLLs—runtime and load-time.

In the case of load-time linking, the library sits idle until an explicit call is made to it. When this happens, the program that called it will perform whatever functions it needs and then, when the library is no longer needed, it is unloaded and remains idle until called upon again. These types of libraries are also referred to as out-of-process or new process servers.

Runtime linking is very similar to load-time linking; however, when the library is a runtime library, it is called with the LoadLibrary function. It then uses the GetProcAddress method to identify the address that is used in launching the library's functions.

> > Hint
> > The Microsoft documentation often refers to libraries that use runtime linking as ISAPI DLLs, but this is a can be confusing. Remembering that ISAPI stands for "Internet Server API," understand that a runtime library can be used in a number of ways that are completely unrelated to Microsoft's Internet Server, or even the Internet itself. An ISAPI .dll is not limited to use on an ActiveX Web server.

In an HTTP server, runtime ISAPI libraries are loaded when the HTTP server is loaded and then shares resources with it by running in the server's process. This eliminates a significant amount of overhead normally associated with CGI scripts. CGIs run in a process separate from the server—demanding equal access to the system resources. Finally, when the library is not needed anymore, it can be unloaded.
>

> > Note:
> > A simple printout of the code for an OLE .DLL could continue for as much as a hundred or more pages, and the documentation on all of its features could extend much farther. Therefore, in the following sections I will focus on the parts of an OLE .DLL that is specific to ISAPI.

As you see, ISAPI DLLs are loaded and unloaded as necessary by the HTTP daemon. When a call is made to an ISAPI library it is loaded into memory. Then, when the server decides that it no longer needs that process, it unloads it, freeing up memory and resources for other processes. Alternatively, the DLL can be "preloaded" by the server so that when the first user attempts to access it, there won't be a pause when it's loaded.

####
In-Process Versus New Process

A significant difference between the way CGI and ISAPI DLLs are run is the addresses in which they are loaded.

In the case of CGIs, they are loaded completely separate from the server process. This is called running in a new process.

In the case of ISAPIs, they are loaded into the same process as the HTTP server. This economizes memory use by avoiding all of the overhead associated with running several different processes in several different areas of memory.

From a system administrator's standpoint, the whole daemon will run smoother and will be less prone to bottlenecks when multiple simultaneous connections are initiated by remote clients.

There is another, very powerful advantage to running ISAPI processes. When a .DLL is first called, be it CGI or ISAPI, it is loaded into memory and run. In ISAPI, if the .DLL is still loaded and several other clients also request it, it will not need to load another copy of itself for each request. CGI needs to run a separate instance for each request, but ISAPI does not.

####
HTTP and ISAPI Interaction

From a user standpoint, the making of a request to and the receiving of data from an ISAPI server is done exactly the same as with CGI. This is as it ought to be, because the client's browsers are using the HTML and HTTP standards for queries and responses.

The browsers don't know or care if the server script is CGI, ISAPI, Perl, or a custom proprietary script. They send and receive their data according to the World Wide Web Consortium's standards—not some unofficial "standard" proposed by Microsoft, Netscape, or anyone else.

> > The Browser Wars
> > As Netscape continues to try to win Microsoft's market share, and Microsoft tries to create globally acceptable Internet products, the competition has become so fierce that Netscape has even gone so far as to complain to the U.S. Department of Justice about Microsoft's progress.
> > In their eagerness to beat the competition, however, each has implemented features in its own browser that have not been accepted by the Internet standards committees. Microsoft (with its BGSound tag) and Netscape (with its strange use of the Object tag) have made the presentation of Internet content inconsistent between browsers. (Although Microsoft's visual display remains compliant, Netscape does not currently display embedded objects properly. Netscape won't play Microsoft's BGSounds, but this usually will not interfere with content presentation.)
> > This extreme competition has, in many cases, forced content providers to keep what amounts to two or three copies of their Web site available online so that Netscape users can view content geared toward that browser, Internet Explorer users can view content geared toward that browser, and users with text-only browsers can view content geared toward their browsers.
> > These inconsistencies are a prime example of how Internet consumers can suffer when individual companies forsake established standards and try to lead the pack instead of working with it.

Although the data and procedures used by ISAPI are similar to those of CGI, from a programmer's standpoint the information is passed back and forth in a very different way. The reason for this is the OLE nature of ISAPIs.

Theses advanced OLE features also make the process much more complex, and fall well outside the scope of anything with which a new user may be familiar. However, because ISAPI is such a powerful feature of the ActiveX family of technologies, I am including it here.

> > Hint
> > If you want to go on to develop these and other types of OLE applications, it is recommended that you make use of the MSDN (Microsoft Developer's Network) line of CD-ROMs. There are several levels to MSDN, but you will find most of what you need for OLE programming at Level 2. When you obtain an MSDN subscription, Microsoft provides you with (depending on your subscription level) copies of all of their APIs, copies of all of their operating systems, and copies of all of their BackOffice network servers.

#####
The Extension Control Block

The Extension Control Block (ECB) is ISAPI's equivalent of StdIn and StdOut. It is a data structure that performs the passing of data from a client to the script and back. The actual data that is in this includes everything you would have sent and received through StdIn/StdOut plus some.

In the ECB structure are variables such as Query_String, Path_Info, and Path_Translated. In addition, this structure includes several functions that are used to pass information back and forth. These functions include GetServerVariable, WriteClient, and ReadClient.

> > Note
> > For you OLE programmers out there, you will need to keep in mind as you write your ISAPI servers that the files must be multithreadable. Complete information on this can be found in the MSDN Level 2 CD-ROMs or just about any manual on Win32 OLE programming. If you are not already an OLE Programmer, you may wish to explore this area of programming.

#####
Entry Points

Every ISAPI DLL requires certain entry points . Entry points are features of an object server through which the DLL will interact with the rest of the system. They include GetExtensionVersion, HTTPExtensionProc, TerminateExtension, and a set of return values.

######
GetExtensionVersion

This is the first process called when the HTTP daemon attempts to run an ISAPI server. If the DLL does not support it, the whole process will fail.

######
HTTPExtensionProc

This process is called in response to every client request. It can be compared to Visual Basic's Sub_Main feature because it runs as soon as the DLL is loaded. It uses the ReadClient callback functions to read the client data.

When the ISAPI server gets this data, it can then go about figuring out what it is supposed to do with it.

######
Return Values

After the ISAPI server has done whatever it was written to do, it needs to return a value indicating its status to the daemon. This status will indicate whether the request is still pending, if there was an error, or that the process has been completed successfully.

One type of return value that you will want to make sure to use is the data to be sent back to the client using the WriteClient or ServerSupportFunction.

######
TerminateExtension

This process is the exact opposite of the HTTPExtensionProc process. It is run when the DLL is to be shut down and is very useful for freeing up system resources.

Just because your program has run its course and is ready to be unloaded doesn't necessarily mean that every process it initiated is complete. When the DLL makes a call to other OLE servers on the machine, those servers may get hung up or otherwise fail to exit properly. The TerminateExtension process provides a place where programmers can put any code to clean up the mess left behind when these errors occur.

Failure to take advantage of this process can put your system in a resource crunch. As each of the different programs and processes are executed, they take up a certain amount of memory and/or processor time. If these keep getting loaded and are never unloaded, they will tie up more and more of your system. Eventually your 128MB Web server could be left with only 2MB or 3MB of memory available—the rest being reserved for those incomplete processes and threads that were not cleaned up.

#####
ISAPI Functions

Within the HTTPExtensionProc process are several functions that can be called to read and set information about the current connection.

######
GetServerVariable

GetServerVariable is the function ISAPIs use to retrieve information for which a CGI would have used an environment variable. This includes information about the current connection as well as any server-specific information.

######
WriteClient

This function, like its namesake and counterpart in CGI, is used to send output to the client host. When the function is complete, it will return a boolean (True/False) value indicating whether the operation was successful. If it was not, and it returns a False value, you can use the GetLastError function to find out the nature of the problem.

######
ReadClient

The ReadClient function is another function that has a namesake counterpart. It is very similar to the WriteClient CGI process. It is used to read the information that the client sends through the HTTP connection. When this function is used, it will return a boolean response indicating whether it was successful.

If the ReadClient function returns a False response, it means that there was some sort of problem. The server can then use the GetLastError function to determine the nature of the problem. The opposite would seem to be indicated by a True response, but this is not necessarily going to be the case every time.

When the ReadClient function returns a True response, it can either mean that the function was successful, or it could mean that the Windows socket closed before the operation was complete. If the latter is the case, and the socket timed out or was otherwise shut down prematurely, the ReadClient will return a True response, but at the same time, the data it retrieves will be 0 bytes in length.

The reason for this seemingly illogical way of handling a premature closure of the socket is due to the fact that in the event of a failure without a closed socket, you may want to retry the ReadClient function until it works properly. However, if you keep retrying to ReadClient when the socket is closed and you keep returning a False value, the server will get stuck in an infinite loop.

When the function reports the process as successful, but with a 0-length output, then a retry won't be triggered. The server will then try to read the data that was returned (or the data that was not returned, in this case) and, seeing that it is 0 bytes long, this result can be used as a trigger to check for a closed socket.

####
Considerations for Building an ISAPI DLL

After you have completed the basic functionality of your ISAPI OLE server, there are a few points you should take into consideration. These points are best left for the rewriting and debugging process. How they are implemented depends on the purpose of the server. They are not supposed to be the framework within which to write the program.

#####
HTTPExtensionProc

Avoiding confusion of the HTTPExtensionProc with the CGI StdIn, you will want to make sure that each of the server variables is taken from the ECB data structure and that you are not referencing environment variables—as you would do with CGI.

In this process you will receive a pointer to the ECB data, which is the only parameter passed. Then you can use the GetServerVariable feature to access whichever variables you need in your ISAPI. The ISAPI can also use the ReadClient feature to retrieve data from the remote host that requested the process.

#####
Access Violations

You can't debug an OLE server enough, but you sure better try. In the case of ISAPI servers , this is particularly critical because an ill-performing ISAPI that runs in the same process as the daemon can bring the system down if it tries to perform an OLE function on something that is not ready for it. One area where this type of debugging is of special importance is in an environment where several ISAPI OLE servers are used.

As with CGIs, there can be (and usually is) more than one ISAPI server that you will want to make available to your users. When multiple ISAPIs are running, they stand a risk of bumping into each other and trying to modify the same bit of data at the same time.

When testing your ISAPI server, you will want to make sure that you test it—not only alone, but also in combination with other ISAPI servers that will be on the same machine. To resolve access violations, and to prevent them in the first place, you should obtain a copy of the Win32 API. This document details many different features of Windows that keep the OLE programmer and his project out of trouble. A few of them are described here.

#####
DLLMain

This type of entry function is called by an ActiveX Web daemon during the LoadLibrary and FreeLibrary processes. In it you should have any information necessary to both get the ISAPI server up and running, and to bring it back down and unload it.

#####
Logging

The ECB structure uses a field named lpszLogData to provide information for logging of activity by the ISAPI OLE server. When your ISAPI needs to record log data, it is usually best to log at least some information to the server's log. Doing this provides the system administrators for the Web daemons the information they need to determine the cause of any mysterious ISAPI-related problems.

If you log your information where the system administrators can see it, they will be better equipped to lay blame in the proper place without too much fishing around. It is very easy for a system administrator to kick your ISAPI server back to you and blame it for all kinds of problems if you are not logging to his logs and a problem occurs. Logging to this file also provides a way for the system administrator to track the use of different OLE servers and determine which ones are used and which are not.

####
Converting CGI to ISAPI

CGIs and ISAPIs share a common purpose—server-side scripting. Although they perform very similar purposes, converting your older CGI applications to new ISAPI ones involves a technological shift from command-line-oriented programming to object-oriented programming.

You won't have to change the logic of your gateway interface—although you will have to change much of the programming syntax used to create it.

Converting the other way however, from ISAPI to CGI, would not be quite so simple—if it were even possible. Taking an ISAPI and converting it to CGI could be impossible in many cases because ISAPI takes advantage of many OLE features with which CGI is utterly incapable of dealing.

Let's take a look at some of the considerations you will need to take in converting your CGI into an ISAPI OLE server.

The following conversion points are by no means to be used as a complete process for creating an OLE server. To create an OLE server requires many advanced OLE skills that are not unique to ActiveX.

#####
StdIn/StdOut to ECB

CGI receives its input from the StdIn features. You should go through your ISAPI project, ensuring that it retrieves this data from the lpbData field of the ECB, and through use of the ReadClient callback function instead of StdIn.

Then, when execution of the CGI is complete and it is ready to return its results, it sends signals through StdOut. This is done by sending Status: ### XXXX (where # is an integer and X is a character) through the WriteClient method.

You should find these places within your project and make sure that you use one of the ISAPI methods to send data to the client. This is done by using the WriteClient method, defined in the ECB. This method is very similar to the CGI equivalent by the same name. Alternatively, you can use the HSW_REQ_SEND_RESPONSE_HEADER feature of the ServerSupportFunction.

If your CGI uses Location: or URL: to return a prior existing file, these processes need to be replaced with their ISAPI equivalents within the ServerSupportFunction. This includes HSE_REQ_SEND_URL for files that are local to the server and HSE_REQ_SEND_URL_REDIRECT_RESP for files that are on a remote server or other unknown location .

###
Summary

In this chapter you have become acquainted with server-side scripting. The lessons here deal with CGI and ISAPI scripts, but other scripts (such as Perl and LISP) can be used also.

Both CGI and ISAPI pass infomration between a Web server and a Web client (usually a browser). The information for CGI is formatted exactly the same as for ISAPI because the information that flows back and forth across the Net must conform to the HTTP standard. The difference between CGI and ISAPI is in how the information is handled on the server.

Most CGI parameters can be sent through environment variables; if not, information can be passed on the command line.

In the case of ISAPI, information is passed through OLE interfaces defined in the ISAPI library file.

ISAPI is a feature of ActiveX that works on an Internet server. It has certain benefits over CGI. When several clients request the same CGI process at the same time, a separate instance of the CGI must be run for each client request. An ISAPI need only have one instance of itself loaded to service multiple simultaneous requests. Also, a CGI runs in a process separate from the server, while ISAPIs run within the server process.

All in all, this allows a server to run more server scripts faster using ISAPI over CGI.

###
Q&A

- Q When creating an OLE ISAPI into a .EXE file and attempting to register it with the RegSvr32 utility, I get application errors. Why is this?
- A This is an error that has been reported frequently throughout alpha, beta, and even the final release phases of the ActiveX SDK. Compiling your OLE server as a .DLL instead of an .EXE always seems to cure it, but nobody can say for sure yet why this is so.
- Q This chapter talked about ISAPI as an extension to CGI, is this the same as an ISAPI filter?
- A No but there are many similarities. They both are compiled into .DLL files and the syntax for their functions is very similar (for example, filters use GetFilterVersion and HTTPFilterProc, whereas ISAPI extensions use GetExtensionVersion and HTTPExtensionProc).
  The purpose of an ISAPI filter is to monitor all incoming requests to the HTTP server. If a condition you specified in the filter occurs (such as a request from a specific IP), the filter process is run. This can be extremely useful for monitoring activity or rejecting certain hosts from the server.
- Q Are there any tools for making the creation of ISAPI extensions any easier?
- A Yes, thank goodness. Visual C++ 4.1 introduced an AppWizard (Application Wizard) that can be used to create ISAPI extensions—as well as a number of other ActiveX aids. Without this tool, manually coding all of the features of an ActiveX OLE server can be tremendously time-consuming.
- Q I'm not a C++ programmer, but I have written many OLE applications in Visual Basic. Will I need to rewrite them for C++ in order to make use of their OLE features over the Web?
- A No. Microsoft provides a .DLL called OLEISAPI.DLL that allows you to run processes that are exposed to OLE without rewriting them for ISAPI.
  This is done through the action attribute of the <FORM> tag. The action is specified like so:

    Action = OLEISAPI.DLL/[ServerName].[ClassName].[MethodName]

- If you have a server that is registered as TheServer, a class called DoIt, and a method called FastReturn, you would write out the action attribute parameter like so:

    Action = OLEISAPI.DLL/TheServer.Doit.FastReturn

- Q I wrote an OLE .DLL in Visual Basic that I am running on my Internet Information Server. I decided to change a few things in it and recompile. This resulted in an "Access Denied" error. What happened?
- A When OLEI SAPI calls your .DLL it and then finishes with it, it leaves the library in memory. To recompile your VB .DLL, you will need to shut down the Web service before you try to recompile your library. Note that in Windows NT, network server applications can be run as a "service". This means that they do not require any program to be run. They are practically part of the operating system and are as transparent to the user as File and Printer Sharing is to the Windows 95 user.)

###
Workshop

Using a site such as Yahoo! (http://www.yahoo.com) or Deja News (http://www.dejanews.com), create a customized HTML form that will search its database. Visit its site and observe the HTML source for its forms. This is called reverse engineering.

###
Quiz

1. What do CGI and ISAPI stand for?
2. What is the purpose shared by an ISAPI extension and a CGI?
3. What file extension identifies a file as an interface to ODBC?
4. What file extension identifies a file as a template within which to return the results of an IDC query?
5. Can Visual Basic be used to create ISAPI DLLs?
6. What commands are used by ISAPI DLLs to retrieve information from and send information to a client connection?
7. Why are CGIs and ISAPIs kept in a directory apart from the rest of the Web pages?
8. What character, when present, causes the HTTP daemon to pass the query string as environment variables rather than command-line parameters?
9. What two types of files can be used as ISAPI extensions?
10. What is the advantage of running an in-process server rather than a new process or out-of-process server?